

function getInputSelection(el) {
    var start = 0, end = 0, normalizedValue, range,
        textInputRange, len, endRange;

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        start = el.selectionStart;
        end = el.selectionEnd;
    } else {
        range = document.selection.createRange();

        if (range && range.parentElement() == el) {
            len = el.value.length;
            normalizedValue = el.value.replace(/\r\n/g, "\n");

            // Create a working TextRange that lives only in the input
            textInputRange = el.createTextRange();
            textInputRange.moveToBookmark(range.getBookmark());

            // Check if the start and end of the selection are at the very end
            // of the input, since moveStart/moveEnd doesn't return what we want
            // in those cases
            endRange = el.createTextRange();
            endRange.collapse(false);

            if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
                start = end = len;
            } else {
                start = -textInputRange.moveStart("character", -len);
                start += normalizedValue.slice(0, start).split("\n").length - 1;

                if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
                    end = len;
                } else {
                    end = -textInputRange.moveEnd("character", -len);
                    end += normalizedValue.slice(0, end).split("\n").length - 1;
                }
            }
        }
    }

    return {
        start: start,
        end: end
    };
}

function offsetToRangeCharacterMove(el, offset) {
    return offset - (el.value.slice(0, offset).split("\r\n").length - 1);
}

function setInputSelection(el, startOffset, endOffset) {
    el.focus();
    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        el.selectionStart = startOffset;
        el.selectionEnd = endOffset;
    } else {
        var range = el.createTextRange();
        var startCharMove = offsetToRangeCharacterMove(el, startOffset);
        range.collapse(true);
        if (startOffset == endOffset) {
            range.move("character", startCharMove);
        } else {
            range.moveEnd("character", offsetToRangeCharacterMove(el, endOffset));
            range.moveStart("character", startCharMove);
        }
        range.select();
    }
}

function opReturn(operand) {
	
	if(operand=='^')
	{
		return 1;
	}
	else if(operand=='_')
	{
		return 2;
	}
	
}

function normalizeLevel(level) {
	if(level>5) {
		return 5;
	}
	return level;
		
}


function childrenWidth(element) {

	var temp1=null,temp2=null;
	
	if(element.children('[inherence=2]').length>0&&element.children('[inherence=1]').length>0) 
	{
		temp1=element.children('[inherence=1]').last();
		temp2=element.children('[inherence=2]').last();
		return Math.max(parseInt(temp1.css("left"),10)+temp1.width(),parseInt(temp2.css("left"),10)+temp2.width());
	}
	else if(element.children('[inherence=2]').length>0)
	{
		temp2=element.children('[inherence=2]').last();
		return parseInt(temp2.css("left"),10)+temp2.width();
	}
	else if(element.children('[inherence=1]').length>0)
	{
		temp1=element.children('[inherence=1]').last();
		return parseInt(temp1.css("left"),10)+temp1.width();
	}
	else {
		return 0;
	}
	
}

//recursively finding width
function totalWidth(element) {
	if(element.children().length>0) {
		return childrenWidth(element); 
	}
	else {
		return element.width();		
	}
}

function returnLeftOffset(parentElement,op) {

// finding element with the same inherence
	var lastChildElement=parentElement.children('[inherence='+op.toString()+']').last();
	
	
	if(lastChildElement.length>0) //it exists
	{
		return parseInt(lastChildElement.css("left"),10)+totalWidth(lastChildElement);
	}
	else //not existing
	{
		return parentElement.is("span")?parentElement.width():0;
	}
}


function runCompile(parent,level,op,textString){
	var text=textString;
// read through it once, get the position of brackets and pairing them.
	var len=text.length;
	var bracketStart=len, bracketEnd=len;
	var bracketCount=0;
	var pairs=[]; // making an empty array for storign all positions of pairs.
	var substringRecursive=''; //for recursion
	var tempChild;
	var bottomOffset=0;
	var leftOffset=0;
	for (var i=0;i<len;i++)
	{
//		alert(bracketCount);
		if(text.charAt(i)=='{')
		{
			if(i>0&&text.charAt((i-1))!='\\')
			{
				bracketCount++;	
			}
			else if(i==0)
			{
				bracketCount++;	
			}
			if(bracketCount==1) // the first {
			{
				bracketStart=i;
			}
		}
		else if(text.charAt(i)=='}')
		{
			if(i>0&&text.charAt((i-1))!='\\')
			{
				bracketCount--;	
			}
			else if(i==0)
			{
				bracketCount--;	
			}
			if(bracketCount==0) // the last }
			{
				bracketEnd=i;
			}
		}
		else
		{
			;
		}
		if(bracketCount==0&&(bracketEnd-bracketStart)>0) // when a pair is found
		{
			pairs.push({start:bracketStart, end:bracketEnd});
			
			bracketStart=len;
			bracketEnd=len;
			bracketCount==0;
		}
	}
	
// Normalized level
	
	level=normalizeLevel(level);
	
	if (bracketCount!=0)
	{
		alert('error!');
	}
	$('#debug').text('#: '+pairs.length.toString());
	
// we have stored the positions of all first-level pairs of {}s 

// read through it twice to build up <span>
	var startOffset=0;
// determine the nature of operator
	startOffset=1; //considering ^ and _ only for now.
// add string to parent

	if(op==1) {
		bottomOffset=parent.height()*1/2;
	}
	else if(op==2) {
		bottomOffset=-parent.height()/4;
	}
	
	var oldWidth=0;
	
	for (i=0;i<len;i++)
	{	
		leftOffset=returnLeftOffset(parent,op);
		if(pairs.length==0) { // when there is no {} pairs
		    tempChild=$('<span'+' inherence="'+op.toString()+'"'+' style="position: absolute; bottom: '+bottomOffset.toString()+'px;'+' left: '+leftOffset.toString()+'px;"'+' class="'+'level_'+level.toString()+'">'+text.charAt(i)+'</span>').appendTo(parent);
		    if(parent.attr('width')) {
				oldWidth=parseInt(parent.attr('width'));  
		    }
		    parent.attr('width',oldWidth+tempChild.width());


		}
		else if(i<pairs[0].start-startOffset) {
		    tempChild=$('<span'+' inherence="'+op.toString()+'"'+' style="position: absolute; bottom: '+bottomOffset.toString()+'px; left: '+leftOffset.toString()+'px;"'+' class="'+'level_'+level.toString()+'">'+text.charAt(i)+'</span>').appendTo(parent);
		    if(parent.attr('width')) {
				oldWidth=parseInt(parent.attr('width'));   
		    }
		    parent.attr('width',oldWidth+tempChild.width());

		}
		else if(i==pairs[0].start-startOffset){ // starting the local recursion 
			substringRecursive=text.substring(pairs[0].start+1, pairs[0].end);
			runCompile(parent.children().last(),level+1,opReturn(text.charAt(i)),substringRecursive);	
			i=pairs[0].end;
			pairs.shift();
				
		}
	}
			

	
};



function keypress(e) {
	if(e.ctrlKey || e.metaKey)
    {
        return;
    }
    var keyCode = e.which;
//    alert(keyCode);
    if(keyCode==94||keyCode==95) // taking care of ^ and _
    	{
    	    var sel = getInputSelection(this);
    	    var val = this.value;
            this.value = val.slice(0, sel.start) + String.fromCharCode(keyCode) + "{}" + val.slice(sel.end);

            // Move the caret
            setInputSelection(this, sel.start+2, sel.start+2);
            return false;
		}
	else if(keyCode==123||keyCode==125) // taking care of { and }
	{
		    var sel = getInputSelection(this);
    	    var val = this.value;
            this.value = val.slice(0, sel.start) +"\\"+ String.fromCharCode(keyCode) + val.slice(sel.end);

            // Move the caret
            setInputSelection(this, sel.start+2, sel.start+2);
            return false;
	}

}

$('#formula').keypress(keypress);
$('#formula').keyup(function () {
	$('#compiled').empty();
	if($('#compiled').attr('width')) {
		$('#compiled').attr('width',0);  
	}
	runCompile($('#compiled'),0,0,$('#formula').val());
});

function PrepareEditor() {
	$('#formula').focus();
};

$(document).ready(PrepareEditor);

